/*
 * Copyright (C) 2009 Dimitrios C. Michalakos
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.restsql.db;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * GenericForeignKeyInfo can be extended by another class to get information about the relations of a table.
 * @author dimitris@jmike.gr
 * @author jiann.lu@yahoo.com
 */
public class GenericForeignKeyInfo {

    /* @param relations can answer these questions:
    - is table A related to table B?
    - which foreign key is used to connect table A to table B?
    Please not that relations can contain only one foreign key.
    In the rare case of multiple foreign keys between table A and table B, only one random foreign key is returned.
    A case of multiple foreign keys between table A and table B is this:
    - Consider table person with one column: id.
    - Consider table relative with two columns: person1 and person2.
    - Column person1 is a foreign key to table person.
    - Column person2 is a foreign key to table person. */
    protected Map<String, Integer> index = new HashMap<String, Integer>();//<foreign key name, internal id>
    //protected Map<String, String> relations = new HashMap<String, String>();//<table1-table2, foreign key name>
    protected Map<String, List<String>> relations = new HashMap<String, List<String>>();//<table1-table2, foreign key name>
    protected String[] table1;
    protected String[] column1;
    protected String[] table2;
    protected String[] column2;

    /**
     * Tests if the specified foreign key exists in database.
     * @param foreignKey The name of the foreign key.
     * @return true if foreign key exists, false if not.
     */
    public boolean exists(String foreignKey) {
        return index.containsKey(foreignKey);
    }

    /**
     * Tests if the specified tables are related.
     * @param t1 The name of the first table.
     * @param t2 The name of the second table.
     * @return true if tables are related, false if not.
     */
    public boolean areRelated(String t1, String t2) {
        return relations.containsKey(t1 + "-" + t2) || relations.containsKey(t2 + "-" + t1);
    }

    /**
     * Returns a two (2) dimensional array containing the columns of the related tables.
     * @param t1 The name of the first table.
     * @param t2 The name of the second table.
     * @return A two (2) dimensional String array.
     * @throws SQLException
     */
    public String[][] getColumns(String t1, String t2) throws SQLException {
        List<String> foreignKeys = relations.get(t1 + "-" + t2);//try to find relation t1-t2
        ArrayList colList = new ArrayList();
        if (foreignKeys != null && foreignKeys.size() > 0) {//relation t1-t2 exists
            for (int ix = 0; ix < foreignKeys.size(); ix++) {
                //System.out.println(t1 + "-" + t2 + " relation found.");
                Integer pos = index.get(foreignKeys.get(ix));
                colList.add(new String[]{column1[pos], column2[pos]});
            }

        } else {//relation t1-t2 does not exist
            foreignKeys = relations.get(t2 + "-" + t1);//try to find relation t2-t1
            if (foreignKeys != null && foreignKeys.size() > 0) {//relation t2-t1 exists
                for (int ix = 0; ix < foreignKeys.size(); ix++) {
                    //System.out.println(t1 + "-" + t2 + " relation found.");
                    Integer pos = index.get(foreignKeys.get(ix));
                    colList.add(new String[]{column1[pos], column2[pos]});
                }
            } else {//relation t2-t1 does not exist
                SQLExceptionState state = SQLExceptionState.TABLES_NOT_RELATED;
                throw new SQLException("Table " + t1 + " is not related to table " + t2 + ".", state.name(), state.code());
            }
        }      
        return (String[][]) colList.toArray(new String[colList.size()][2]);
    }

    /**
     * Returns a two (2) dimensional array containing the columns of the specified foreign key.
     * @param foreignKey The name of the foreign key.
     * @return A two (2) dimensional String array.
     * @throws SQLException
     */
    public String[][] getColumns(String foreignKey) throws SQLException {
        if (index.containsKey(foreignKey)) {
            Integer pos = index.get(foreignKey);
            String[][] a = new String[1][2];
            a[0][0] = column1[pos];
            a[0][1] = column2[pos];

            return a;
        } else {
            SQLExceptionState state = SQLExceptionState.FOREIGN_KEY_NOT_FOUND;
            throw new SQLException("Foreign key " + foreignKey + " cannot be found in database.", state.name(), state.code());
        }
    }
}
